package com.chushouya.manager.service.admin.impl;



import com.general.framework.core.lang.*;
import com.chushouya.common.constant.CommonStatusEnum;
import com.chushouya.common.support.Contexts;
import com.general.framework.core.enums.DelFlagEnum;
import com.general.framework.core.enums.StatusEnum;
import com.general.framework.core.exception.Ex;
import com.chushouya.manager.dao.entity.DeptEntity;
import com.chushouya.manager.dao.repository.AdminUserRepository;
import com.chushouya.manager.dao.repository.DeptRepository;
import com.chushouya.manager.dto.admin.dept.DeptListDTO;
import com.chushouya.manager.dto.admin.dept.DeptListQuery;
import com.chushouya.manager.dto.admin.dept.DeptSaveDTO;
import com.chushouya.manager.dto.admin.dept.DeptTreeDTO;
import com.chushouya.manager.service.admin.DeptService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class DeptServiceImpl implements DeptService {

    @Resource
    private DeptRepository deptRepository;

    @Resource
    private AdminUserRepository adminUserRepository;

    @Override
    public List<DeptListDTO> selectDeptList(DeptListQuery query) {
        return Beans.copyList(deptRepository.selectDeptList(query), DeptListDTO.class);
    }

    @Override
    public DeptSaveDTO getDeptDetail(Long deptId) {
        Check.notNull(deptId, "deptId can not be null");
        return Beans.copy(deptRepository.selectByPrimaryKey(deptId), DeptSaveDTO.class);
    }

    @Override
    public List<DeptTreeDTO> getDeptTree() {
        DeptListQuery query = new DeptListQuery();
        query.setStatus(CommonStatusEnum.Enable.value());
        List<DeptEntity> allDeptList = deptRepository.selectDeptList(query);
        if (Lists.isEmpty(allDeptList)) {
            return Lists.emptyList();
        }
        return this.buildDeptTree(allDeptList);
    }

    private List<DeptTreeDTO> buildDeptTree(List<DeptEntity> allDeptList) {
        List<DeptTreeDTO> deptTree = new ArrayList<>();
        for (DeptEntity deptEntity : allDeptList) {
            if (Objects.equals(deptEntity.getParentId(), Numbers.LONG_ZERO)) {
                DeptTreeDTO root = new DeptTreeDTO();
                root.setDeptId(deptEntity.getDeptId());
                root.setDeptName(deptEntity.getDeptName());
                this.recursionChildDept(root.getDeptId(), root, allDeptList);
                deptTree.add(root);
            }
        }
        return deptTree;
    }

    /**
     * 递归
     */
    private void recursionChildDept(Long parentDeptId, DeptTreeDTO parentDept, List<DeptEntity> allDeptList) {
        List<DeptEntity> childrenDept = allDeptList.stream().filter(d -> Objects.equals(parentDeptId, d.getParentId())).collect(Collectors.toList());
        if (Lists.isNotEmpty(childrenDept)) {
            List<DeptTreeDTO> children = new ArrayList<>();
            for (DeptEntity childDept : childrenDept) {
                DeptTreeDTO child = new DeptTreeDTO();
                child.setDeptId(childDept.getDeptId());
                child.setDeptName(childDept.getDeptName());
                this.recursionChildDept(child.getDeptId(), child, allDeptList);
                children.add(child);
            }
            parentDept.setChildren(children);
        }
    }


    @Override
    public Long addDept(DeptSaveDTO dept) {
        if (this.checkDeptNameUnique(dept)) {
            throw Ex.business("部门名称重复");
        }
        DeptEntity deptEntity = Beans.copy(dept, DeptEntity.class);
        this.setDeptAncestors(deptEntity);
        deptEntity.setDelFlag(DelFlagEnum.normal.getValue());
        deptEntity.setCreateBy(Contexts.getUserContext().getUserName());
        deptEntity.setCreateTime(Dates.getTimeNow());
        deptRepository.insertSelective(deptEntity);
        return deptEntity.getDeptId();
    }

    private void setDeptAncestors(DeptEntity deptEntity) {
        if (Longs.notNullAndZero(deptEntity.getParentId()) && deptEntity.getParentId() > Numbers.LONG_ZERO) {
            DeptEntity parentDept = deptRepository.selectByPrimaryKey(deptEntity.getParentId());
            if (Objects.equals(parentDept.getStatus(), StatusEnum.disable.value())) {
                throw Ex.business("部门停用，不允许新增");
            }
            deptEntity.setAncestors(parentDept.getAncestors() + "," + deptEntity.getParentId());
        } else {
            deptEntity.setAncestors("0");
        }
    }

    @Override
    public Long editDept(DeptSaveDTO dept) {
        Check.notNull(dept.getDeptId(), "deptId can not be null");
        if (this.checkDeptNameUnique(dept)) {
            throw Ex.business("部门名称重复");
        }
        DeptEntity deptEntity = Beans.copy(dept, DeptEntity.class);
        this.setDeptAncestors(deptEntity);
        deptEntity.setUpdateBy(Contexts.getUserContext().getUserName());
        deptEntity.setUpdateTime(Dates.getTimeNow());
        deptRepository.updateByPrimaryKeySelective(deptEntity);
        return deptEntity.getDeptId();
    }

    @Override
    public void removeDept(Long deptId) {
        if (this.hasChildByDeptId(deptId)) {
            throw Ex.business("存在下级部门,不允许删除");
        }
        if (this.checkDeptExistUser(deptId)) {
            throw Ex.business("部门存在用户,不允许删除");
        }
        DeptEntity update = new DeptEntity();
        update.setDeptId(deptId);
        update.setDelFlag(DelFlagEnum.delete.getValue());
        deptRepository.updateByPrimaryKeySelective(update);
    }

    @Override
    public List<Long> selectChildDeptIdList(Long deptId) {
        List<DeptEntity> childDeptList = deptRepository.selectChildDeptList(deptId);
        if (Lists.isEmpty(childDeptList)) {
            return Lists.emptyList();
        }
        return childDeptList.stream().map(DeptEntity::getDeptId).collect(Collectors.toList());
    }

    @Override
    public List<Long> selectAllChildDeptIdList(Long deptId) {
        List<Long> ids = selectChildDeptIdList(deptId);
        if (Lists.isEmpty(ids)) {
            return Lists.emptyList();
        }
        for (Long id : ids) {
            ids.addAll(selectAllChildDeptIdList(id));
        }
        return ids;
    }

    @Override
    public Long selectIdByName(String name) {
        return deptRepository.selectIdByName(name);
    }

    private boolean hasChildByDeptId(Long deptId) {
        int count = deptRepository.selectChildDeptCount(deptId);
        return count > Numbers.INTEGER_ZERO;
    }

    private boolean checkDeptExistUser(Long deptId) {
        int count = adminUserRepository.selectDeptUserCount(deptId);
        return count > Numbers.INTEGER_ZERO;
    }

    private boolean checkDeptNameUnique(DeptSaveDTO dept) {
        DeptListQuery query = new DeptListQuery();
        query.setDeptName(dept.getDeptName());
        if (Longs.notNullAndZero(dept.getDeptId())) {
            query.setIdNotEqualTo(dept.getDeptId());
        }
        DeptEntity deptEntity = deptRepository.selectOneRole(query);
        return Objects.nonNull(deptEntity);
    }
}
